Repository navigation
fix(internal): XML (TwiML) serialization drops characters outside XML 1.0 in all SDK generators - #18423
Conversation
… 1.0 in all SDK generators Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ng; Ruby test and C# System.Text import Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
There was a problem hiding this comment.
AI Review Summary
Adds XML 1.0 Char filtering across seven SDK generators plus regenerated seed fixtures. The approach is consistent and well-tested, but the C# StripInvalidXmlChars has an inverted surrogate-pair check that silently drops every valid astral character (emoji, CJK ext), and the Go filter drops the UTF-8 replacement rune that strings.Map emits for invalid bytes rather than the original byte.
- 🔴 1 critical issue(s)
- 🟡 2 warning(s)
- 🔵 1 suggestion(s)
Review Scope
- Mode: Full pull request
- Range:
Full pull request through c30bf4544eda489d955ac897b16480c9fd5541ac - Current range coverage: Complete
- Cumulative pull request coverage: Complete
This review is complete for the current scope. Addressing all critical and warning findings above satisfies the review; suggestions are optional. Request another review only if subsequent changes introduce new behavior or materially expand the pull request's scope.
There was a problem hiding this comment.
✅ Devin resolved all 3 findings on c30bf45
Fixed by Devin (3)
- Invalid comments still break XML output
- Root sibling comments remain invalid
- Namespace declarations bypass character filtering
SDK Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
- C#: explicit high/low surrogate guards, sibling comments sanitized - TS/Python/Java/Ruby/Go: comments filtered through the shared helper - PHP: namespace declaration URIs filtered before setAttributeNS - Java: rename c -> codePoint; regression tests in all generators Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…strip-invalid-chars Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> # Conflicts: # generators/typescript/utils/core-utilities/src/core/xml/serialize.ts # seed/ts-sdk/ts-xml-twiml/forward-compatible-enums/src/core/xml/serialize.ts # seed/ts-sdk/ts-xml-twiml/no-custom-config/src/core/xml/serialize.ts # seed/ts-sdk/ts-xml-twiml/serde-layer/src/core/xml/serialize.ts
…strip-invalid-chars Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> # Conflicts: # generators/csharp/base/src/asIs/XmlUtils.Template.cs # seed/csharp-sdk/csharp-xml-twiml/no-custom-config/src/SeedApi/Core/XmlUtils.cs # seed/csharp-sdk/csharp-xml-twiml/use-undiscriminated-unions/src/SeedApi/Core/XmlUtils.cs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Description
Linear ticket: N/A (Twilio TwiML parity tracker, issue 31)
Twilio reported that a value containing a control character (e.g.
\x01) is emitted verbatim into TwiML by the generated PHP SDK, producing XML that no parser accepts (the legacy SDK had the same bug). Every XML serializer in the seven SDK generators now drops characters that are not legal in XML 1.0 before escaping, so the same input yields the same, valid output in every language.Kept:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]. Dropped: everything else (\x00–\x08,\x0B,\x0C,\x0E–\x1F,\uFFFE,\uFFFF, lone surrogates). Applies to text nodes, attribute values and (where the serializer supports them) comments.Changes Made
core/xml/serialize.ts:escapeXmlstripsINVALID_XML_CHARS(/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/gu) before escaping; text/attribute escaping behaviour otherwise unchanged (quotes stay literal in text).xml_utilities.py:escape/quoteattrwrapxml.sax.saxutilsand remove_INVALID_XML_CHARSfirst.XmlWriter.escape: iterates code points, skips!isXmlChar(cp), appends the rest withappendCodePoint(so surrogate pairs survive, lone surrogates are dropped).core/xml.go:strings.Mapfilter withisXmlChar(r rune)beforexml.EscapeText.XmlUtils.Serialize: serializes a filtered clone (WithoutInvalidXmlChars) coveringXText,XCommentand attributes;StripInvalidXmlCharsusesXmlConvert.IsXmlChar+XmlConvert.IsXmlSurrogatePairand only allocates aStringBuilderwhen something has to be removed (net462/net8.0/netstandard2.0 compatible).XmlUtils::stripInvalidXmlChars(preg_replacewith theuflag), applied to text, comments and attributes (setDomAttribute).Internal::Xml::Utils:INVALID_XML_CHARSremoved inescape_text;escape_attributebuilds on it."a\x00b\x1Fc\td"→abc\td, attribute"man\x01"→man), unreleased changelog entries for all 7 generators, regenerated*-xml-twimlseed fixtures.Testing
ts-xml-twiml(3/3 fixtures) and its xml unit tests (24 passed)pytest tests/utils/test_xml_utilities.py(35 passed), mypy/ruffjava-xml-twimlgradle tests pass;XmlElement.builder("Say").attribute("voice","man\u0001").text("a\u0000b\u001Fc\td")→<Say voice="man">abc d</Say>go test ./internal/generator/sdk/core/...csharp-xml-twiml(both fixtures),dotnet test255 passedphp-xml-twiml, phpunit 150 tests OK, phpstan no errorsruby-xml-twiml, 701 runs / 0 failures, rubocop cleanLink to Devin session: https://app.devin.ai/sessions/311fe13ae5434245ada665a9b824809b
Open in Devin Desktop: https://app.devin.ai/desktop/session/311fe13ae5434245ada665a9b824809b?variant=devin
Requested by: @cadesark